home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / QuickDraw / Virtual Sphere 1.0.1 / Virtual Sphere Sample Code 1.1 / SampleAdditional.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-25  |  14.7 KB  |  418 lines  |  [TEXT/MPS ]

  1. /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  2. /* SampleAdditional.c
  3. /*
  4. /* This file contains routines to replace the standard ones in Sample.c
  5. /*
  6. /* Author: Michael Chen, Human Interface Group / ATG
  7. /* Copyright © 1991-1993 Apple Computer, Inc.  All rights reserved.
  8. /*
  9. /* Part of Virtual Sphere Sample Code Release v1.1
  10. /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
  11.  
  12. #ifndef    __SAMPLEADDITIONAL__
  13. #include "SampleAdditional.h"
  14. #endif
  15.  
  16. #ifndef __TOOLUTILS__
  17. #include <ToolUtils.h>
  18. #endif
  19.  
  20. #ifndef __FIXMATH__
  21. #include <FixMath.h>
  22. #endif
  23.  
  24. #ifndef __ERRORS__
  25. #include <Errors.h>
  26. #endif
  27.  
  28. #ifndef __GRAF3D__
  29. #include <Graf3D.h>
  30. #endif
  31.  
  32. #ifndef __MENUS__
  33. #include <Menus.h>
  34. #endif
  35.  
  36. #ifndef __OFFSCREEN__
  37. #include "Offscreen.h"
  38. #endif
  39.  
  40. #ifndef __MyMath__
  41. #include "MyMath.h"
  42. #endif
  43.  
  44. #ifndef    __GRAPHICS3D__
  45. #include "Graphics3D.h"
  46. #endif
  47.  
  48. #ifndef    __VIRTUALSPHERE__
  49. #include "VirtualSphere.h"
  50. #endif
  51.  
  52. #include "Sample.h"
  53.  
  54. #define    Long2Fix(x)            (Fixed)(x<<16)                    /* override standard trap call */
  55. #include "ObjectData.h"
  56.  
  57. /* Define values for the Virtual Sphere cue circle.
  58.  * In a real application, the cue circle should resize to the currently selected object */ 
  59. #define    kSphereCenterH    150
  60. #define    kSphereCenterV    150
  61. #define    kSphereRadius    130
  62.  
  63. /* Routine global to this file (module) only */
  64. static void DoRotation (WindowPtr window, EventRecord *event, Matrix4D    objectMatrix);
  65.  
  66. /* Variables global to this file (module) only */
  67. static Port3DPtr    lgThePort3DPtr;                /* global pointer used to remember the current Port3D */
  68. static Port3D        lgMyPort3D;
  69. static Matrix4D        lgObjectMatrix;
  70. static GWorldPtr    lgOffscreenGWorld = nil;
  71.  
  72. /*=================================================================================================
  73. /* Initialize3D
  74. /*
  75. /* Set up Graf3D, create an offscreen buffer for the window and display parameters.
  76. /*-------------------------------------------------------------------------------------------------*/
  77. void Initialize3D (WindowPtr window)
  78. {
  79.     Rect        globalRect;
  80.     Boolean        gWorldAvailable;
  81.     
  82.     /* Setup offscreen buffer */
  83.     if (InitializeOffscreen (&gWorldAvailable) != noErr) {
  84.         MessageAlertAndQuit ("\pInitOffscreen returned an error.");
  85.     }
  86.     if (!gWorldAvailable) {
  87.         MessageAlertAndQuit ("\pThis application requires 32-bit Color Quickdraw or System 7.");
  88.     }
  89.         
  90.     if (CheckOffscreenForWindow (&lgOffscreenGWorld, 0, window) != noErr) {
  91.         /* Note CheckOffscreenForWindow() has already set lgOffscreenGWorld to nil. */
  92.         MessageAlert ("\pThere is not enough memory to do double buffering.");
  93.         gDoubleBuffer = false;
  94.     } else {
  95.         gDoubleBuffer = true;
  96.     }
  97.  
  98.     /* Initialize our 3D graphics rountines */
  99.     if (InitializeGraphics3D() != noErr) {
  100.         MessageAlertAndQuit ("\pInitialzeGraphics3D.");
  101.     }
  102.     
  103.     /* Initialize Graf3D */
  104.     InitGrf3d (&lgThePort3DPtr);    /* Must call */
  105.     SetPort (window);                /* Make sure OpenPort3D uses the current GrafPort */
  106.     Open3DPort (&lgMyPort3D);        /* Open3DPort fills in the lgMyPort3D record with 
  107.                                      * appropriate values (including setting the field
  108.                                      * lgMyPort3D.grPort to the current GrafPort */
  109.     SetPort3D (&lgMyPort3D);        /* Make sure we are using this Port3D */
  110.  
  111.     /* Make the 3D viewport the same size as the window */
  112.     ViewPort (&(lgMyPort3D.grPort->portRect));
  113.     
  114.     /* Set up the 3D viewing pyrimid.  Note the top and bottom parameters are flipped so
  115.      * that y increases going up */
  116.     #define kXMin        -200
  117.     #define kXMax         200
  118.     #define kYMin        -200
  119.     #define kYMax         200
  120.     LookAt (Long2Fix(kXMin), Long2Fix(kYMax), Long2Fix(kXMax), Long2Fix(kYMin));
  121.     ViewAngle (Long2Fix (25));
  122.     
  123.     /* Unset the optimization flag within Graf3D which "remembers" if lgMyPort3D.xForm is
  124.      * identity or not. This is needed since we modify lgMyPort3D.xForm directly via the
  125.      * Matrix2XfMatrix() call below.  We never call any of the Graf3D routines which
  126.      * indirectly modify the xForm matrix. */
  127.      Scale (Long2Fix (1), Long2Fix (1), Long2Fix (1));    /* Actually any Graf3D transform call
  128.                                                           * that generates a indentity matrix
  129.                                                           * will do */
  130.  
  131.     /* Initialize the object matrix to identity.  Note the object matrix is in floating point.
  132.      * This matrix is then converted and stored into Graf3D's xForm matrix (in Fixed point format). */
  133.     lgObjectMatrix [0][0] = lgObjectMatrix [1][1] = lgObjectMatrix [2][2] = lgObjectMatrix [3][3] = 1;
  134.     lgObjectMatrix [0][1] = lgObjectMatrix [0][2] = lgObjectMatrix [0][3] = 
  135.     lgObjectMatrix [1][0] = lgObjectMatrix [1][2] = lgObjectMatrix [1][3] = 
  136.     lgObjectMatrix [2][0] = lgObjectMatrix [2][1] = lgObjectMatrix [2][3] = 
  137.     lgObjectMatrix [3][0] = lgObjectMatrix [3][1] = lgObjectMatrix [3][2] = 0;
  138.     Matrix2XfMatrix (lgObjectMatrix, lgMyPort3D.xForm);
  139.  
  140.     /* Setup default drawing styles for the 3D object. */
  141.     gObjectDisplayed = iHouse;
  142.     gRenderingStyle = iFlatShading;            
  143.     gDoBackfacedPolygonRemoval = true;
  144.     globalRect = window->portRect;
  145.     LocalToGlobalRect (&globalRect);
  146.     gDrawInColor = gMac.hasColorQD && (ScreenDepth (&globalRect) > 1);
  147. }
  148.  
  149. /*=================================================================================================
  150. /* CleanUp3D
  151. /*
  152. /* Clean up 3D stuff before quiting application.
  153. /*-------------------------------------------------------------------------------------------------*/
  154. void CleanUp3D ()
  155. {
  156.     FreeOffscreen (lgOffscreenGWorld);
  157.     FreeGraphics3D ();
  158. }
  159.  
  160. /*=================================================================================================
  161. /* AdjustAdditionalMenus
  162. /*
  163. /* Enable / disable menus items related to this 3D sample program
  164. /*-------------------------------------------------------------------------------------------------*/
  165. void AdjustAdditionalMenus ()
  166. {
  167.     Boolean        isAppWindow;
  168.     MenuHandle    menu;
  169.     
  170.     isAppWindow = !IsDAWindow (FrontWindow());
  171.  
  172.     menu = GetMHandle (mObject);
  173.     EnableDisableItem (menu, iCube,                    isAppWindow);
  174.     EnableDisableItem (menu, iIcosahedron,             isAppWindow);
  175.     EnableDisableItem (menu, iHouse,                   isAppWindow);
  176.     CheckItem         (menu, iCube,                    gObjectDisplayed == iCube);
  177.     CheckItem         (menu, iIcosahedron,             gObjectDisplayed == iIcosahedron);
  178.     CheckItem         (menu, iHouse,                   gObjectDisplayed == iHouse);
  179.  
  180.     menu = GetMHandle (mOptions);
  181.     EnableDisableItem (menu, iLineDrawing,             isAppWindow);
  182.     EnableDisableItem (menu, iFlatShading,             isAppWindow);
  183.     EnableDisableItem (menu, iFlatShadingWithOutline,  isAppWindow);
  184.     EnableDisableItem (menu, iDrawInBW,                   isAppWindow);
  185.     EnableDisableItem (menu, iDrawInColor,             isAppWindow && gMac.hasColorQD);
  186.     EnableDisableItem (menu, iBackfacedPolygonRemoval, isAppWindow);
  187.     EnableDisableItem (menu, iDoubleBuffer,            isAppWindow && (lgOffscreenGWorld != nil));
  188.     CheckItem         (menu, iLineDrawing,             gRenderingStyle == iLineDrawing);
  189.     CheckItem         (menu, iFlatShading,             gRenderingStyle == iFlatShading);
  190.     CheckItem         (menu, iFlatShadingWithOutline,  gRenderingStyle == iFlatShadingWithOutline);
  191.     CheckItem         (menu, iDrawInBW,                   !gDrawInColor);
  192.     CheckItem         (menu, iDrawInColor,               gDrawInColor);
  193.     CheckItem         (menu, iBackfacedPolygonRemoval, gDoBackfacedPolygonRemoval);
  194.     CheckItem         (menu, iDoubleBuffer,            gDoubleBuffer);
  195. }
  196.  
  197. /*=================================================================================================
  198. /* CheckSystemConfiguration
  199. /*
  200. /* If system configuration is not right, alert user and exit to Finder.
  201. /* Must be universal code
  202. /*-------------------------------------------------------------------------------------------------*/
  203. #ifdef applec
  204. #pragma push                    /* MPW: save compiler flags         */
  205. #pragma processor 68000            /* Generate 68000 instructions only */
  206. #endif
  207. void CheckSystemConfiguration ()
  208. {
  209.     #ifdef THINK_C                /* THINK C: Generate 68020 instructions… */
  210.     #pragma options(!mc68020)    /* …NOT!  Silly way of saying 68000      */
  211.     #endif                        /* instructions only.  Note this pragma  */
  212.                                 /* is defined only until end of routine. */
  213.  
  214.     if (qUseFPUand020 && !(gMac.hasFPU)) {
  215.         /* Should use string resource to show this message! */
  216.         MessageAlertAndQuit ("\pSorry.  You can only run this application on a Mac with a '020 processor and math coprocessor.");
  217.     }
  218. }
  219. #ifdef applec
  220. #pragma pop                        /* MPW: restore compiler flags */
  221. #endif
  222.  
  223. /*=================================================================================================
  224. /* DoAdditionalMenuCommand
  225. /*
  226. /* Deal with menus selections related to this 3D sample program
  227. /*-------------------------------------------------------------------------------------------------*/
  228. void DoAdditionalMenuCommand (long menuResult)
  229. {
  230.     short        menuID;                /* the resource ID of the selected menu */
  231.     short        menuItem;            /* the item number of the selected menu */
  232.     WindowPtr    window;
  233.  
  234.     menuID = HiWord (menuResult);    /* use macros for efficiency to... */
  235.     menuItem = LoWord (menuResult);    /* get menu item number and menu number */
  236.     window = FrontWindow ();
  237.  
  238.     switch (menuID) {
  239.         case mObject:
  240.             switch (menuItem) {
  241.                 case iCube:
  242.                     gObjectDisplayed = iCube;
  243.                     break;
  244.                 case iIcosahedron:
  245.                     gObjectDisplayed = iIcosahedron;
  246.                     break;
  247.                 case iHouse:
  248.                     gObjectDisplayed = iHouse;
  249.                     break;
  250.             }
  251.             InvalRect (&window->portRect);
  252.             break;
  253.         case mOptions:
  254.             switch (menuItem) {
  255.                 case iLineDrawing:
  256.                     gRenderingStyle = iLineDrawing;            
  257.                     break;
  258.                 case iFlatShading:
  259.                     gRenderingStyle = iFlatShading;            
  260.                     break;
  261.                 case iFlatShadingWithOutline:
  262.                     gRenderingStyle = iFlatShadingWithOutline;            
  263.                     break;
  264.                 case iBackfacedPolygonRemoval:
  265.                     gDoBackfacedPolygonRemoval = !gDoBackfacedPolygonRemoval;
  266.                     break;
  267.                 case iDoubleBuffer:
  268.                     gDoubleBuffer = !gDoubleBuffer;
  269.                     break;
  270.                 case iDrawInBW:
  271.                     gDrawInColor = false;
  272.                     break;
  273.                 case iDrawInColor:
  274.                     gDrawInColor = true;
  275.                     break;
  276.             }
  277.             InvalRect (&window->portRect);
  278.             break;
  279.     }
  280. }
  281.  
  282. /*=================================================================================================
  283. /* DoContentClick
  284. /*
  285. /* Called when there is a mouse down in the window content.
  286. /* In this sample app, we only need to rotate the displayed object.  In a more
  287. /* complex app, you would  probably need to determine which object is clicked and
  288. /* figure out what operation you should apply to that object.
  289. /*-------------------------------------------------------------------------------------------------*/
  290. void DoContentClick (WindowPtr window, EventRecord *event)
  291. {
  292.     DoRotation (window,    event, lgObjectMatrix);
  293. }
  294.  
  295. /*=================================================================================================
  296. /* DoRotation
  297. /*
  298. /* Called when there is a mouse down in the window content.
  299. /* Use the Virtual Sphere to rotate the current object on the screen.
  300. /* In a 3D graphics program, an objects usually has associated with it a "modeling" matrix.
  301. /* An object is rotated by modifying its modeling matrix.  This is done here by repeatedly
  302. /* concatenating the rotation determined by the Virtual Sphere to the object's matrix while
  303. /* the user is dragging the mouse.
  304. /*-------------------------------------------------------------------------------------------------*/
  305. static void DoRotation (WindowPtr window, EventRecord *event, Matrix4D    objectMatrix)
  306. {
  307.     Point        p, q;
  308.     short        dx, dy;
  309.     Point        sphereCenter; 
  310.     Integer        sphereRadius; 
  311.     Matrix4D    tempMatrix;
  312.     Matrix4D    rotationMatrix;
  313.     
  314.     SetCursor (*GetCursor(crossCursor));
  315.     
  316.     p = event->where;
  317.     GlobalToLocal (&p);            /* Get the mouse down point in local coordinates. */
  318.     
  319.     /* Figure out where to place the Virtual Sphere cue.
  320.      * In this sample app., the cue is always centered on the window with a fixed size.
  321.      * In an general app., you will need to determine the location and size of cue
  322.      * (in screen coordinates) to surround the object */
  323.     sphereCenter.h = kSphereCenterH; 
  324.     sphereCenter.v = kSphereCenterV; 
  325.     sphereRadius   = kSphereRadius;
  326.     
  327.     while (StillDown()) {                                
  328.         GetMouse (&q);
  329.         dx = q.h - p.h;
  330.         dy = q.v - p.v;
  331.         if (dx != 0 || dy != 0) {
  332.             /* Determine the rotation matrix from the mouse movement */
  333.             VirtualSphere (p, q, sphereCenter, sphereRadius, rotationMatrix);
  334.  
  335.             /* Concatenate the new rotation with the current rotation */
  336.             MultiplyMatrix (objectMatrix, rotationMatrix, tempMatrix);
  337.             CopyMatrix (tempMatrix, objectMatrix);
  338.             
  339.             /* The next routine may be called if the objectMatrix really gets "out of shape"
  340.              * due to numeric inaccuracies from repeated matrix multiplications.  This does not
  341.              * happen in this demo program so the call is commented out */
  342.             /* OrthogonalizeRotationMatrix (objectMatrix); */
  343.             
  344.             /* Update the window */
  345.             DrawWindow (window);
  346.             
  347.             p = q;        /* Remember previous mouse point for next iteration. */
  348.         }
  349.     }
  350. }
  351.  
  352. /*=================================================================================================
  353. /* DrawWindow
  354. /*
  355. /* Draw the current 3D object and surround it with the Virtual Sphere cue.  In this sample
  356. /* application, the object is always centered on the window with a fixed size.
  357. /* In an general app., you will need to determine the location and size of sphere
  358. /* to surround the object.
  359. /*-------------------------------------------------------------------------------------------------*/
  360. void DrawWindow (WindowPtr window)
  361. {
  362.     Rect sphereRect;
  363.     
  364.     SetPort3D (&lgMyPort3D);
  365.     /* Convert and store our matrix into the Graf3D matrix */
  366.     Matrix2XfMatrix (lgObjectMatrix, lgMyPort3D.xForm);
  367.  
  368.     if (gDoubleBuffer) BeginDrawingOffscreen (lgOffscreenGWorld, window);
  369.  
  370.     EraseRect (&qd.thePort->portRect);
  371.  
  372.     /* Draw the object */
  373.     switch (gObjectDisplayed) {
  374.         case iCube:
  375.             DrawPolyNet (&gCubeData);
  376.             break;
  377.         case iIcosahedron:
  378.             DrawPolyNet (&gIcosahedronData);
  379.             break;
  380.         case iHouse:
  381.             DrawPolyNet (&gHouseData);
  382.             break;
  383.     }
  384.  
  385.     /* Draw Virtual Sphere cue around the object */
  386.     SetRect (&sphereRect, kSphereCenterH-kSphereRadius, kSphereCenterV-kSphereRadius,
  387.                           kSphereCenterH+kSphereRadius, kSphereCenterV+kSphereRadius); 
  388.     ForeColor (magentaColor);
  389.     FrameOval (&sphereRect);
  390.  
  391.     if (gDoubleBuffer) EndDrawingOffscreen (lgOffscreenGWorld, window);
  392. }
  393.  
  394. /*=================================================================================================
  395. /* UpdateWindow
  396. /*
  397. /* Deal with update event.  Reallocate the offscreen buffer if the window has been moved
  398. /* or the bit-depth has been changed.  Then draw the window content if needed.
  399. /*-------------------------------------------------------------------------------------------------*/
  400. void UpdateWindow (WindowPtr window)
  401. {
  402.     if (gDoubleBuffer) {
  403.         if (CheckOffscreenForWindow (&lgOffscreenGWorld, 0, window) == memFullErr) {
  404.             MessageAlert ("\pThere is not enough memory to do double buffering for this screen depth.");
  405.             if (lgOffscreenGWorld == nil) gDoubleBuffer = false;
  406.         }
  407.     }
  408.  
  409.     BeginUpdate (window);
  410.     
  411.     if (!EmptyRgn (window->visRgn)) {
  412.         /* Updating needs to be done */
  413.         DrawWindow (window);
  414.     }    
  415.  
  416.     EndUpdate (window);
  417. }
  418.